﻿using System;
using System.Collections.Specialized;
using System.Web;
using Restful.Net.Serialization;

namespace Restful.Net
{
    /// <summary>
    /// Represents the HttpRequest with the needed variables to make a proper rest implementation.
    /// </summary>
    internal class RestRequest : IRequest
    {
        /// <summary>
        /// The serializer if any to be used when deserializing the request body.
        /// </summary>
        private readonly ISerializer serializer;

        /// <summary>
        /// Initializes a new instance of the <see cref="RestRequest"/> class.
        /// </summary>
        /// <param name="httpRequest">The HTTP request.</param>
        /// <param name="serializer">The serializer.</param>
        internal RestRequest(HttpRequestBase httpRequest, ISerializer serializer)
        {
            this.serializer = serializer;
            RequestBase = httpRequest;
            RestVariables = new NameValueCollection();
        }

        /// <summary>
        /// Gets the request base that exposes the underlying HttpRequest.
        /// </summary>
        public HttpRequestBase RequestBase
        {
            get;
            private set;
        }

        /// <summary>
        /// Gets the URI of the http request
        /// </summary>
        public Uri Uri
        {
            get
            {
                return RequestBase.Url;
            }
        }

        /// <summary>
        /// Gets the htpt verb of the http request
        /// </summary>
        public HttpVerb Verb
        {
            get
            {
                switch (RequestBase.HttpMethod)
                {
                    case "GET":
                        return HttpVerb.Get;
                    case "POST":
                        return HttpVerb.Post;
                    case "PUT":
                        return HttpVerb.Put;
                    case "HEAD":
                        return HttpVerb.Head;
                    case "PATCH":
                        return HttpVerb.Patch;
                    case "DELETE":
                        return HttpVerb.Delete;
                    case "OPTIONS":
                        return HttpVerb.Options;
                    default:
                        throw new InvalidOperationException(string.Format("Unknown Http verb:{0}", RequestBase.HttpMethod));
                }
            }
        }

        /// <summary>
        /// Gets the rest variables retrieved from the Path + query string that matches
        /// the Uri template of the method that will be invoked.
        /// </summary>
        public NameValueCollection RestVariables
        {
            get;
            private set;
        }

        /// <summary>
        /// Gets the If-None-Match http header used together with Etag for caching purposes
        /// </summary>
        /// <value></value>
        public string IfNoneMatch
        {
            get
            {
                return RequestBase.Headers["If-None-Match"];
            }
        }

        /// <summary>
        /// Gets the request body of the incoming http request
        /// </summary>
        /// <param name="type">The type to deserialize the request body as.</param>
        /// <returns>The body of the request deserialized as the given type.</returns>
        /// <exception cref="InvalidOperationException">If Http Verb is not Patch, Post or Put</exception>
        public object GetRequestBody(Type type)
        {
            if (Verb != HttpVerb.Patch && Verb != HttpVerb.Post && Verb != HttpVerb.Put)
            {
                throw new InvalidOperationException("GetRequest body is only valid on either Patch, Post or Put Verb");
            }

            return serializer.Deserialize(type, RequestBase.InputStream);
        }
    }
}
